package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.entity.Employee;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;


import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 实现公共字段的自动填充
 *    一. 定义注解
 *        1.定义注解@AutoFil,给定一个属性value,接收OperationType类型
 *        2.这个value属性是用来标记的方法到底是添加方法还是更新方法
 *    二. 使用注解
 *        1.在dao层,找到添加和更新方法,分别打上注解
 *     三.定义AOP切面增强类,处理增强
 *        1.定义切面类,打注解
 *          @Component,把这个对象交给IOC容器管理
 *          @Aspect,表示他是一个切面增强类
 *        2.定义方法,使用环绕增强,对dao层进行增强
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    @Around("@annotation(com.sky.annotation.AutoFill)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //1. 对方法的参数进行补充

        //1.0 获取方法的参数,一般来说添加或者更新方法,只有一个参数
        Object param = joinPoint.getArgs()[0];


        //1.1 必须要知道现在是添加方法还是更新方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        //1.2  获取方法身上的注解
        Method method = signature.getMethod();
        AutoFill autoFill = method.getAnnotation(AutoFill.class);

        //1.3 判断注解的属性值
        if (OperationType.INSERT == autoFill.value()) { // 新增
            // 反射调用
            Method m1 = param.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class);
            Method m2 = param.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
            Method m3 = param.getClass().getDeclaredMethod("setCreateUser", Long.class);
            Method m4 = param.getClass().getDeclaredMethod("setUpdateUser", Long.class);

            m1.invoke(param,LocalDateTime.now());
            m2.invoke(param,LocalDateTime.now());
            m3.invoke(param,BaseContext.getCurrentId());
            m4.invoke(param,BaseContext.getCurrentId());
        } else {  // 更新
            Method m2 = param.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
            Method m4 = param.getClass().getDeclaredMethod("setUpdateUser", Long.class);

            m2.invoke(param,LocalDateTime.now());
            m4.invoke(param,BaseContext.getCurrentId());
        }

        //2. 调用目标方法
        return joinPoint.proceed(new Object[]{param});
    }
    // /**
    //  * 切入点
    //  */
    // @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    // public void autoFillPointCut() {
    // }
    //
    // /**
    //  * 前置通知，在通知中进行公共字段的赋值
    //  */
    // @Before("autoFillPointCut()")
    // public void autoFill(JoinPoint joinPoint) {
    //     log.info("开始进行公共字段自动填充...");
    //
    //     //获取到当前被拦截的方法上的数据库操作类型
    //     MethodSignature signature = (MethodSignature) joinPoint.getSignature();//方法签名对象
    //     AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获得方法上的注解对象
    //     OperationType operationType = autoFill.value();//获得数据库操作类型
    //
    //     //获取到当前被拦截的方法的参数--实体对象
    //     Object[] args = joinPoint.getArgs();
    //     if (args == null || args.length == 0) {
    //         return;
    //     }
    //
    //     Object entity = args[0];
    //
    //     //准备赋值的数据
    //     LocalDateTime now = LocalDateTime.now();
    //     Long currentId = BaseContext.getCurrentId();
    //
    //     //根据当前不同的操作类型，为对应的属性通过反射来赋值
    //     if (operationType == OperationType.INSERT) {
    //         //为4个公共字段赋值
    //         try {
    //             Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
    //             Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
    //             Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
    //             Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
    //
    //             //通过反射为对象属性赋值
    //             setCreateTime.invoke(entity, now);
    //             setCreateUser.invoke(entity, currentId);
    //             setUpdateTime.invoke(entity, now);
    //             setUpdateUser.invoke(entity, currentId);
    //         } catch (Exception e) {
    //             e.printStackTrace();
    //         }
    //     } else if (operationType == OperationType.UPDATE) {
    //         //为2个公共字段赋值
    //         try {
    //             Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
    //             Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
    //
    //             //通过反射为对象属性赋值
    //             setUpdateTime.invoke(entity, now);
    //             setUpdateUser.invoke(entity, currentId);
    //         } catch (Exception e) {
    //             e.printStackTrace();
    //         }
    //     }
    // }
}